﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Skynet.Contracts;
using Skynet.Models;
namespace Skynet.Services.Extension
{
    [Export]
    public class ExtensionFactory
    {
        [Import]
        private ICaptureInfoRepository _captureInfoRepository = null;
        [ImportMany]
        private Lazy<ICaptureDevice, ICaptureDeviceCapabilies>[] _captureDevices = null;
        private CaptureTypes _runningCaptureTypes;

        public Lazy<ICaptureDevice, ICaptureDeviceCapabilies>[] SupportedCaptureDevices { get; private set; }
        public List<Lazy<ICaptureDevice, ICaptureDeviceCapabilies>> EnabledCaptureDevices { get; private set; }

        public void InitializeCaptureDevices(ExtensionService service)
        {
            // CaptureDevices:
            Console.WriteLine("CaptureDevices:");
            var lastColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.DarkGray;
            var supportedCaptureDevices = new List<Lazy<ICaptureDevice, ICaptureDeviceCapabilies>>();
            if ((_captureDevices == null) || (_captureDevices.Length == 0))
            {
                Console.WriteLine("No Extensions");
                Console.WriteLine();
            }
            else
                foreach (var captureDevice in _captureDevices)
                {
                    var m = captureDevice.Metadata;
                    var d = captureDevice.Value;
                    var isSupported = d.IsSupported;
                    if (isSupported)
                        supportedCaptureDevices.Add(captureDevice);
                    Console.WriteLine("Extension - ID:  {0}", m.ID);
                    Console.WriteLine("          - type:\t\t{0}", d.GetType().Name);
                    Console.WriteLine("          - metric:\t\t{0}", m.Metric);
                    Console.WriteLine("          - captures:\t\t{0}", m.Types.ToString());
                    Console.WriteLine("          - supported:\t\t{0}", isSupported);
                    Console.WriteLine();
                }
            Console.ForegroundColor = lastColor;
            SupportedCaptureDevices = supportedCaptureDevices.ToArray();
        }

        public void SyncEnabledCaptureDevices()
        {
            lock (this)
            {
                if (EnabledCaptureDevices != null)
                    Stop();
                EnabledCaptureDevices = SupportedCaptureDevices
                    .Join(_captureInfoRepository.GetEnabledCaptures(), x => x.Metadata.ID, x => x.ID, (a, b) => a)
                    .OrderByDescending(x => x.Metadata.Metric)
                    .ToList();
            }
            // EnabledCaptureDevices:
            Console.WriteLine("EnabledCaptureDevices:");
            var lastColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.DarkYellow;
            foreach (var captureDevice in EnabledCaptureDevices)
            {
                var m = captureDevice.Metadata;
                Console.WriteLine("Extension - ID:  {0}", m.ID);
            }
            Console.WriteLine();
            Console.ForegroundColor = lastColor;
        }

        public void Sync(ITransport transport, CaptureTypes requestedCaptureTypes)
        {
            if (requestedCaptureTypes == _runningCaptureTypes)
                return;
            lock (this)
            {
                if (requestedCaptureTypes == _runningCaptureTypes)
                    return;
                Stop();
                Start(transport, requestedCaptureTypes);
            }
        }

        private void Stop()
        {
            foreach (var captureDevice in EnabledCaptureDevices)
                if ((captureDevice.Metadata.Types & _runningCaptureTypes) != 0)
                    captureDevice.Value.Stop();
            _runningCaptureTypes = 0;
        }

        private void Start(ITransport transport, CaptureTypes requestedCaptureTypes)
        {
            foreach (var captureDevice in EnabledCaptureDevices)
                if ((captureDevice.Metadata.Types & requestedCaptureTypes) != 0)
                    captureDevice.Value.Start(transport);
            _runningCaptureTypes = requestedCaptureTypes;
        }
    }
}
